package de.ludo.gaming;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.ejb.EJB;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.jws.WebService;

import de.ludo.dao.DAOLocal;
import de.ludo.dto.GameFieldResponse;
import de.ludo.dto.GameFieldTO;
import de.ludo.dto.GameListResponse;
import de.ludo.dto.GameResponse;
import de.ludo.dto.HighscoreResponse;
import de.ludo.dto.PlayerDiceResponse;
import de.ludo.dto.RequestingPlayerListResponse;
import de.ludo.dto.ReturncodeResponse;
import de.ludo.dto.UserLoginResponse;
import de.ludo.dto.UserTO;
import de.ludo.entities.Game;
import de.ludo.entities.Highscore;
import de.ludo.entities.LudoSession;
import de.ludo.entities.Player;
import de.ludo.entities.User;
import de.ludo.exceptions.InvalidLoginException;
import de.ludo.exceptions.LudoException;
import de.ludo.exceptions.NoGameException;
import de.ludo.exceptions.NoSessionException;
import de.ludo.util.DtoAssembler;
import de.ludo.util.Encrypt;
import de.ludo.util.GameStatus;
import de.ludo.util.GameType;

@WebService
@Stateless
@Remote(LudoOnlineIntegration.class)
public class LudoOnlineIntegrationImpl implements LudoOnlineIntegration {

	final String NAME_AI = "Computer";

	@EJB(beanName = "DAO", beanInterface = de.ludo.dao.DAOLocal.class)
	private DAOLocal dao;

	/**
	 * Instance to create DTObject
	 */
	@EJB
	private DtoAssembler dtoAssembler;

	@EJB
	private OutputBean outputBean;

	/**
	 * Method is needed to get a session object in a smaller scope, if sessionId
	 * is known
	 * 
	 * @param sessionId
	 * @return
	 * @throws NoSessionException
	 */
	private LudoSession getSession(int sessionId) throws NoSessionException {
		LudoSession session = dao.findSessionById(sessionId);
		if (session == null)
			throw new NoSessionException("Sie sind nicht eingeloggt.");
		else
			return session;
	}

	/**
	 * Method is needet to get a game object in a smaller scope, if gameId is
	 * known
	 * 
	 * @param gameId
	 * @return
	 * @throws NoGameException
	 */
	private Game getGame(int gameId) throws NoGameException {
		Game game = dao.findGameById(gameId);
		if (game == null)
			throw new NoGameException(
					"Kein Spiel gefunden. Versuchen Sie es mit einem anderem Spiel");
		else
			return game;
	}

	/**
	 * Delivers highscore from database Attentions for programmers: Check if
	 * highscore was found has to be done in calling method
	 * 
	 * @param username
	 * @return Highscore
	 */
	private Highscore getHighscore(String username) {
		return dao.findHighscoreByGameAndName(GameType.Ludo, username);
	}

	/**
	 * Returns a UserLoginResponse if the user is logged in successfully Uses
	 * dtoAssembler to create Transfer Objects for ksoap
	 * 
	 * @return UserLoginResponse
	 */
	@Override
	public UserLoginResponse login(String userName, String pwd) {
		UserLoginResponse logResponse = new UserLoginResponse();
		Encrypt md5 = new Encrypt("SHA-256");
		try {
			User user = dao.findUserByName(userName);
			String helper = md5.do_checksum(pwd);
			if (user != null && user.getPassword().equals(helper)) {
				// Login successfull
				UserTO to = dtoAssembler.createUserTO(user);

				int sessionId = dao.createSession(user.getUsername());

				to.setSessionId(sessionId);
				logResponse.setUser(to);

				// logResponse.setSessionId(sessionId);
			} else {
				throw new InvalidLoginException(
						"Login nicht möglich. Bitte überprüfen Sie Ihre Login-Daten.");
			}
		} catch (LudoException e) {
			logResponse.setMsg(e.getMessage());
			logResponse.setReturnCode(e.getErrorCodeNb());

		}

		return logResponse;

	}

	/**
	 * Method to register a user. New users are added in the Database
	 * automatically.
	 * 
	 * @return UserLoginResponse, new users are automatically logged in. If
	 *         ErrorCode=10, registration was not successfull
	 * 
	 */
	@Override
	public UserLoginResponse register(String userName, String pwd) {
		UserLoginResponse logResponse = new UserLoginResponse();
		User user = dao.findUserByName(userName);
		if (user == null) {

			User newUser = new User(userName, pwd);
			dao.saveUser(newUser);

			Highscore newHigh = new Highscore(userName, 0, GameType.Ludo);
			dao.saveHighscore(newHigh);

			int sessionId = dao.createSession(userName);

			UserTO to = dtoAssembler.createUserTO(newUser);

			to.setSessionId(sessionId);
			logResponse.setUser(to);

		} else {
			UserTO to = dtoAssembler.createUserTO(user);
			logResponse.setUser(to);
		}
		return logResponse;
	}

	/**
	 * Method to log out the user. Session is deleted automatically
	 * 
	 * @return ReturncodeResponse
	 */
	@Override
	public ReturncodeResponse logout(int sessionId) {
		dao.closeSession(sessionId);
		ReturncodeResponse response = new ReturncodeResponse();
		return response;
	}

	/**
	 * Returns a GameListResponse which can be used by the Android client.
	 * 
	 * @return GameListResponse
	 */
	@Override
	public GameListResponse getFreeGames() {
		GameListResponse r = new GameListResponse();
		List<Game> games = this.dao.findGamesByStatus(GameStatus.OPENING);
		r.setGamelist(dtoAssembler.makeDTO(games));
		return r;
	}

	/**
	 * This method creates a new, open game. The requesting user will be set as
	 * YellowPlayer automatically.
	 * 
	 * @return PlayerGameIdMsgResponse
	 */
	@Override
	public GameResponse openNewGame(int sessionId) {
		GameResponse r = new GameResponse();
		try {
			LudoSession session = getSession(sessionId);
			Game g = new Game(session);
			dao.savePlayer(g.getPlayerYellow());
			dao.saveGame(g);
			r.setGame(dtoAssembler.createGameTO(g));
			r.setMsg("Es wurde ein Spiel erstellt. Du kannst es starten oder auf Gegner warten und sie akzeptieren");
		} catch (LudoException e) {
			r.setMsg(e.getMessage());
			r.setReturnCode(e.getErrorCodeNb());
		}
		return r;
	}

	/**
	 * If the available Games are listed, the user can select a game he wants to
	 * enter. This method supplies the Red, Green and Blue Player (always in
	 * this order!). He then will be added to a List in Game Object, so the
	 * DungeonMaster is able to see the requesting Users
	 * 
	 */
	@Override
	public GameResponse enterExistingGame(int sessionId, int gameId) {
		GameResponse response = new GameResponse();
		try {
			Game eG = getGame(gameId);
			LudoSession session = getSession(sessionId);
			eG.addNewRequestingUserId(session);
			dao.updateGame(eG);
		} catch (LudoException e) {
			response.setMsg(e.getMessage());
			response.setReturnCode(e.getErrorCodeNb());
		}

		return response;
	}

	/**
	 * This method asks the game of the YellowPlayer (=dungeonmaster) for a list
	 * of all requesting users. The YellowPlayer then gets a List of names,
	 * which he can accepts as opponents.
	 * 
	 * @return RequestingPlayerListResponse
	 */
	@Override
	public RequestingPlayerListResponse handleRequests(int sessionId, int gameId) {
		RequestingPlayerListResponse r = new RequestingPlayerListResponse();
		try {
			Game eG = getGame(gameId);

			List<LudoSession> userSession = eG.getRequestingSessions();
			String[] list = new String[userSession.size()];

			// Check, if user is allowed to handle any requests
			if (eG.getPlayerYellow().getSessionId() == sessionId) {
				for (int i = 0; i < userSession.size(); i++) {
					LudoSession session = userSession.get(i);
					list[i] = session.getUserName();
				}
				r.setPlayerList(list);
				return r;
			} else {
				throw new LudoException(501, "Sie sind nicht authorisiert");
			}
		} catch (LudoException e) {
			r.setMsg(e.getMessage());
			r.setReturnCode(e.getErrorCodeNb());
		}
		return r;

	}

	/**
	 * 
	 * This method needs the sessionId of the YellowPlayer, the GameId and the
	 * userName of the requesting User
	 * 
	 * @return gameId if succesfull
	 * @return 0 if unsuccesfull
	 * 
	 */
	@Override
	public GameResponse allowUserToEnterTheGame(int ownSessionId,
			String userName, int gameId) {
		GameResponse r = new GameResponse();
		try {
			// Select requiering sessionId and Game by userName and gameId from
			// dao
			int reqSessionId = dao.findSessionIdByUserName(userName);
			Game eG = getGame(gameId);
			LudoSession requestingSession = getSession(reqSessionId);

			// Check if calling player is YellowPlayer
			if (eG.getPlayerYellow().getSessionId() == ownSessionId) {

				if (eG.getPlayerRed() == null) {
					Player rP = new Player(requestingSession,
							PlayerType.PLAYER_RED);
					eG.setPlayerRed(rP);

					// The second requiring user will be transformed into the
					// green player
				} else if (eG.getPlayerGreen() == null) {
					Player gP = new Player(requestingSession,
							PlayerType.PLAYER_GREEN);
					eG.setPlayerGreen(gP);

					// The third requiring user will be transformed into the
					// blue player
				} else if (eG.getPlayerBlue() == null) {
					Player bP = new Player(requestingSession,
							PlayerType.PLAYER_BLUE);
					eG.setPlayerBlue(bP);
					// If the last player is set, the game starts automatically
					// TODO startGame(ownSessionId, gameId);
				}

				eG.removeRequestingUserId(requestingSession);
				dao.updateGame(eG);
				r.setGame(dtoAssembler.createGameTO(eG));
			} else {
				throw new LudoException(501, "Sie sind nicht authorisiert");
			}
		} catch (LudoException e) {
			r.setMsg(e.getMessage());
			r.setReturnCode(e.getErrorCodeNb());
		}

		return r;
	}

	public GameResponse getGameById(int gameId) {
		GameResponse r = new GameResponse();
		try {
			Game eG = getGame(gameId);
			r.setGame(dtoAssembler.createGameTO(eG));
			r.setMsg("Game ladem mit Id: " + gameId);
			r.setReturnCode(0);
		} catch (LudoException e) {
			r.setMsg(e.getMessage());
			r.setReturnCode(e.getErrorCodeNb());
		}

		return r;
	}

	/**
	 * Method for the player to dice. Checks: is the user (sessionId) allowed to
	 * dice? (check with currentPlayer in GameObject)
	 * 
	 * @throws NoGameException
	 */
	@Override
	public PlayerDiceResponse dice(int sessionId, int gameId) {
		PlayerDiceResponse response = new PlayerDiceResponse();

		try {
			Game eG = getGame(gameId);
			if (sessionId == eG.getCurrentPlayer().getSessionId()) {

				// Ask for Support
				LudoIntegrationSupport sup = new LudoIntegrationSupport();

				int diceResult = sup.throwDice();

				if (diceResult == 6) {
					eG.setRemainingAttempts(1);
				} else {
					eG.setRemainingAttempts(eG.getRemainingAttempts() - 1);
				}

				response.setDiceResult(diceResult);
				response.setMsg(diceResult + " gewürfelt");

				int[] possibleCharacters = sup.selectPossibleCharacters(eG,
						diceResult);
				response.setPossibleCharacters(possibleCharacters);

				// next player is already set at this point if the user does not
				// have any attempts left after this one AND he does not have
				// any possible characters to move. If there are possible moves,
				// the next player is set in moveCharacter
				if (eG.getRemainingAttempts() == 0
						&& possibleCharacters.length == 0) {
					eG.setCurrentPlayer(sup.nextPlayer(eG));
					eG.setRemainingAttempts(sup.calculateRemainingAttempts(eG));
					if (eG.getCurrentPlayer().isArtifcialPlayer()) {
						executeArtificialMoves(eG);
					}
				}
				dao.updateGame(eG);
			} else {
				throw new LudoException(999,
						"Sie sind nicht authorisiert zu würfeln");
			}
		} catch (LudoException e) {
			response.setMsg(e.getMessage());
			response.setReturnCode(e.getErrorCodeNb());
		}
		return response;
	}

	/**
	 * This method starts the game. Only the yellow Player is authorized to do
	 * so.
	 * 
	 * The gameBoard is initialized during this method. Futhermore, the status
	 * is set as running and the remaining diceAttempts of the
	 * YellowPlayer(always the beginner) are set to 3.
	 * 
	 * @return PlayerGameIdMsgRespone gameId if successfull, 0 if not
	 *         successfull
	 * @throws NoGameException
	 * 
	 */
	@Override
	public GameFieldResponse startGame(int sessionId, int gameId) {
		GameFieldResponse r = new GameFieldResponse();
		r.setArtificialOpponentPlayer(false);
		LudoIntegrationSupport sup = new LudoIntegrationSupport();
		try {
			Game eG = getGame(gameId);
			// Check, if player is allowed to start the game (is he the yellow
			// player?)
			if (eG.getPlayerYellow().getSessionId() == sessionId) {

				if (eG.getRemainingGamePositions() == 3) {
					Player ai = new Player(true,
							dao.createSession(this.NAME_AI));
					ai.setPlayerName(this.NAME_AI);
					eG.setPlayerRed(ai);
					r.setArtificialOpponentPlayer(true);
				}

				// init the gameBaord
				eG.setGameBoardAsIntArray(sup.initGameBoard(eG));

				// The yellow Player is the "dungeon master" and is always
				// allowed to start the the game
				eG.setCurrentPlayer(eG.getPlayerYellow());

				eG.setRemainingAttempts(3);
				eG.setStatus(GameStatus.RUNNING);

				dao.updateGame(eG);

				r.setGameFieldTO(dtoAssembler.createGameFieldTO(eG));
				r.setUpNext(eG.getCurrentPlayer().getSessionId());
				r.setUpdates(true);
				r.setMsg("Das Spiel wurde gestartet!");
				return r;
			} else {
				throw new LudoException(999,
						"Das Spiel konnte nicht gestartet werden. Sie sind nicht authorisiert");
			}
		} catch (LudoException e) {
			r.setMsg(e.getMessage());
			r.setReturnCode(e.getErrorCodeNb());
		}
		return r;
	}

	@Override
	public GameFieldResponse askForUpdatesOnGameField(int gameId,
			int character1, int character2, int character3, int character4,
			int character5, int character6, int character7, int character8,
			int character9, int character10, int character11, int character12,
			int character13, int character14, int character15, int character16) {
		GameFieldResponse r = new GameFieldResponse();
		int[] gameField = { character1, character2, character3, character4,
				character5, character6, character7, character8, character9,
				character10, character11, character12, character13,
				character14, character15, character16 };
		try {
			Game g = getGame(gameId);
			GameFieldTO dto = dtoAssembler.createGameFieldTO(g);

			if (g.getPlayerYellow() != null) {
				r.setNameYellowPlayer(g.getPlayerYellow().getPlayerName());
			}
			if (g.getPlayerRed() != null) {
				r.setNameRedPlayer(g.getPlayerRed().getPlayerName());
			}
			if (g.getPlayerGreen() != null) {
				r.setNameGreenPlayer(g.getPlayerGreen().getPlayerName());
			}
			if (g.getPlayerBlue() != null) {
				r.setNameBluePlayer(g.getPlayerBlue().getPlayerName());
			}

			r.setGameFieldTO(dto);
			r.setUpNext(g.getCurrentPlayer().getSessionId());
			if (Arrays.equals(dto.getGameField(), gameField)) {
				r.setUpdates(false);
				r.setMsg("Keine Updates vorhanden");
			} else {
				r.setUpdates(true);
				r.setMsg("Updates vorhanden");
			}
		} catch (LudoException e) {
			r.setMsg(e.getMessage());
			r.setReturnCode(e.getErrorCodeNb());
		}
		return r;
	}

	@Override
	public GameListResponse getRunningGames() {
		GameListResponse r = new GameListResponse();
		List<Game> games = this.dao.findGamesByStatus(GameStatus.RUNNING);
		r.setGamelist(dtoAssembler.makeDTO(games));
		return r;
	}

	@Override
	public ReturncodeResponse closeGame(int gameId) {
		this.dao.closeGame(gameId);
		ReturncodeResponse response = new ReturncodeResponse();
		return response;
	}

	@Override
	public GameFieldResponse moveCharacter(int gameId, int sessionId,
			int gameFieldIndex, int diceResult) {
		GameFieldResponse response = new GameFieldResponse();
		LudoIntegrationSupport sup = new LudoIntegrationSupport();
		try {
			Game g = getGame(gameId);
			// new position is calculated
			int newPosition = sup.calculateNewPosition(diceResult,
					gameFieldIndex, g.getCurrentPlayer().getType());
			// new gameBaord is calculated with new position
			int[] gameBoard = sup.move(gameFieldIndex, newPosition,
					g.getGameBoardAsIntArray());
			// new gameBaord is set to Game
			g.setGameBoardAsIntArray(gameBoard);

			// characters of all players are updated
			g.setPlayerYellow(updatePlayerYellowCharacters(g));
			g.setPlayerRed(updatePlayerRedCharacters(g));
			g.setPlayerGreen(updatePlayerGreenCharacters(g));
			g.setPlayerBlue(updatePlayerBlueCharacters(g));

			if (sup.isGameFinished(g)
					&& !g.getCurrentPlayer().isArtifcialPlayer()) {
				Highscore score = getHighscore(g.getCurrentPlayer()
						.getPlayerName());
				score.setScore(score.getScore() + g.getRemainingGamePositions());
				dao.updateHighscore(score);
			}

			if (g.getRemainingAttempts() == 0) {
				Player nextPlayer = sup.nextPlayer(g);
				// current player is updated
				g.setCurrentPlayer(nextPlayer);

				// remaining attemps are calculated, depending of the character
				// positions of the new current player
				g.setRemainingAttempts(sup.calculateRemainingAttempts(g));
			}

			response.setGameFieldTO(dtoAssembler.createGameFieldTO(g));
			response.setUpdates(true);
			response.setUpNext(g.getCurrentPlayer().getSessionId());

			dao.updateGame(g);
			if (g.getCurrentPlayer().isArtifcialPlayer()) {
				executeArtificialMoves(g);
			}

		} catch (NoGameException e) {
			response.setMsg(e.getLocalizedMessage());
			response.setReturnCode(e.getErrorCodeNb());
		}

		return response;
	}

	/**
	 * set yellow characters
	 * 
	 * @param g
	 * @return
	 */
	private Player updatePlayerYellowCharacters(Game g) {
		// 1-4 red, search in g.getGameField
		int[] gameBoard = g.getGameBoardAsIntArray();
		Player yellow = null;

		if (g.getPlayerYellow() != null) {
			yellow = g.getPlayerYellow();
		}

		// Search the Character and update Player
		for (int i = 0; i < gameBoard.length; i++) {
			if (yellow != null && gameBoard[i] == 1) {
				yellow.setCharacterOne(i);
			} else if (yellow != null && gameBoard[i] == 2) {
				yellow.setCharacterTwo(i);
			} else if (yellow != null && gameBoard[i] == 3) {
				yellow.setCharacterThree(i);
			} else if (yellow != null && gameBoard[i] == 4) {
				yellow.setCharacterFour(i);
			}
		}
		return yellow;

	}

	/**
	 * set red characters
	 * 
	 * @param g
	 * @return
	 */
	private Player updatePlayerRedCharacters(Game g) {
		// 1-4 red, search in g.getGameField
		int[] gameBoard = g.getGameBoardAsIntArray();
		Player red = null;

		if (g.getPlayerRed() != null) {
			red = g.getPlayerRed();
		}

		// Search the Character and update Player
		for (int i = 0; i < gameBoard.length; i++) {
			if (red != null && gameBoard[i] == 5) {
				red.setCharacterOne(i);
			} else if (red != null && gameBoard[i] == 6) {
				red.setCharacterTwo(i);
			} else if (red != null && gameBoard[i] == 7) {
				red.setCharacterThree(i);
			} else if (red != null && gameBoard[i] == 8) {
				red.setCharacterFour(i);
			}
		}
		return red;

	}

	/**
	 * set green characters
	 * 
	 * @param g
	 * @return
	 */
	private Player updatePlayerGreenCharacters(Game g) {
		// 1-4 red, search in g.getGameField
		int[] gameBoard = g.getGameBoardAsIntArray();
		Player green = null;

		if (g.getPlayerGreen() != null) {
			green = g.getPlayerGreen();
		}

		// Search the Character and update Player
		for (int i = 0; i < gameBoard.length; i++) {
			if (green != null && gameBoard[i] == 9) {
				green.setCharacterOne(i);
			} else if (green != null && gameBoard[i] == 10) {
				green.setCharacterTwo(i);
			} else if (green != null && gameBoard[i] == 11) {
				green.setCharacterThree(i);
			} else if (green != null && gameBoard[i] == 12) {
				green.setCharacterFour(i);
			}
		}
		return green;

	}

	/**
	 * set blue characters
	 * 
	 * @param g
	 * @return
	 */
	private Player updatePlayerBlueCharacters(Game g) {
		// 1-4 red, search in g.getGameField
		int[] gameBoard = g.getGameBoardAsIntArray();
		Player blue = null;

		if (g.getPlayerBlue() != null) {
			blue = g.getPlayerBlue();
		}

		// Search the Character and update Player
		for (int i = 0; i < gameBoard.length; i++) {
			if (blue != null && gameBoard[i] == 13) {
				blue.setCharacterOne(i);
			} else if (blue != null && gameBoard[i] == 14) {
				blue.setCharacterTwo(i);
			} else if (blue != null && gameBoard[i] == 15) {
				blue.setCharacterThree(i);
			} else if (blue != null && gameBoard[i] == 16) {
				blue.setCharacterFour(i);
			}
		}
		return blue;

	}

	public void executeArtificialMoves(Game g) {
		LudoIntegrationSupport sup = new LudoIntegrationSupport();
		int diceResult = sup.throwDice();
		if (diceResult == 6) {
			g.setRemainingAttempts(1);
		} else {
			g.setRemainingAttempts(g.getRemainingAttempts() - 1);
		}

		int[] possibleChars = sup.selectPossibleCharacters(g, diceResult);
		if (possibleChars.length > 0) {
			int choosenChar = possibleChars[0];
			int newPosition = sup.calculateNewPosition(diceResult, choosenChar,
					PlayerType.PLAYER_RED);
			int[] gameBoard = sup.move(choosenChar, newPosition,
					g.getGameBoardAsIntArray());
			g.setGameBoardAsIntArray(gameBoard);
			g.setPlayerYellow(updatePlayerYellowCharacters(g));
			g.setPlayerRed(updatePlayerRedCharacters(g));
			g.setPlayerGreen(updatePlayerGreenCharacters(g));
			g.setPlayerBlue(updatePlayerBlueCharacters(g));
			dao.updateGame(g);

		}
		if (g.getRemainingAttempts() > 0) {
			executeArtificialMoves(g);
		} else {
			g.setCurrentPlayer(sup.nextPlayer(g));
			g.setRemainingAttempts(sup.calculateRemainingAttempts(g));

		}

		dao.updateGame(g);
	}

	/**
	 * Is called from requesting Player after he asked for permission to enter
	 * the Game
	 * 
	 * @param sessionId
	 * @param gameId
	 * @return returnCode = 0 if user was accepted, returnCode = 1 if permission
	 *         was denied. If 0, GameTO-Object is delivered
	 */
	@Override
	public GameResponse isTheRequestingPlayerAccepted(int sessionId, int gameId) {
		GameResponse r = new GameResponse();
		LudoIntegrationSupport sup = new LudoIntegrationSupport();
		try {
			Game g = getGame(gameId);
			if (sup.checkIfUserWasAccepted(g, sessionId)) {
				r.setReturnCode(0);
				r.setGame(dtoAssembler.createGameTO(g));
				r.setMsg("Ihre Anfrage wurde akzeptiert.");
				return r;
			}
			r.setMsg("Ihre Anfrage wurde abgelehnt.");
			r.setReturnCode(1);
			return r;
		} catch (NoGameException e) {
			r.setMsg(e.getMessage());
			r.setReturnCode(e.getErrorCodeNb());
		}
		return r;
	}

	/**
	 * Is called from player red, blue and green if they were accepted for the
	 * game.
	 * 
	 * @param sessionId
	 * @param gameId
	 * @return returnCode = 0 if the game has started. returnCode = 1 if the
	 *         game is not started yet
	 */
	@Override
	public GameFieldResponse isTheGameStarted(int sessionId, int gameId) {
		GameFieldResponse r = new GameFieldResponse();
		try {
			Game g = getGame(gameId);

			if (g.getStatus().ordinal() == GameStatus.RUNNING.ordinal()) {
				r.setReturnCode(0);
				r.setArtificialOpponentPlayer(false);
				r.setGameFieldTO(dtoAssembler.createGameFieldTO(g));
				r.setUpNext(g.getCurrentPlayer().getSessionId());
				r.setUpdates(true);
				return r;
			}
			r.setReturnCode(1);
			r.setMsg("Das Spiel wurde noch nicht gestartet");
			return r;
		} catch (NoGameException e) {
			r.setMsg("Der Tisch wurde aufgelöst");
			r.setReturnCode(e.getErrorCodeNb());
		}

		return r;
	}

	/**
	 * Is called from requesting player who does not want to play anymore
	 * 
	 * @param sessionId
	 * @param gameId
	 * @return returnCode = 0 if deleted was successful, 1 if it was not and the
	 *         game has already started (=> if he leaves despite this fact, he
	 *         will get negative points for the game
	 */
	@Override
	public ReturncodeResponse removeRequestingPlayerFromList(int sessionId,
			int gameId) {
		ReturncodeResponse r = new ReturncodeResponse();

		try {
			Game g = getGame(gameId);
			LudoSession s = getSession(sessionId);
			if (g.getRequestingSessions().contains(s)) {
				g.getRequestingSessions().remove(s);
				dao.updateGame(g);
				r.setReturnCode(0);
				r.setMsg("Ihre Anfrage wurde abgelehnt.");
				return r;
			}
			r.setReturnCode(1);
			return r;

		} catch (NoGameException | NoSessionException e) {
			r.setMsg(e.getMessage());
			r.setReturnCode(e.getErrorCodeNb());
		}
		return r;
	}

	@Override
	public ReturncodeResponse leaveRunningGame(int sessionId, int gameId) {
		ReturncodeResponse r = new ReturncodeResponse();
		LudoIntegrationSupport sup = new LudoIntegrationSupport();
		try {
			Game g = getGame(gameId);
			LudoSession session = dao.findSessionById(sessionId);
			String userNameFromLeaving = session.getUserName();
			Player player = null;
			int[] gameBoard = g.getGameBoardAsIntArray();
			int countPlayer = 0;
			if (g.getPlayerYellow() != null) {
				countPlayer++;
				if (g.getPlayerYellow().getPlayerName()
						.equals(userNameFromLeaving)) {
					player = g.getPlayerYellow();
					gameBoard = deleteCharacterFromGameBoard(gameBoard, player);
					if (g.getCurrentPlayer().equals(player)) {
						g.setRemainingAttempts(0);
						g.setCurrentPlayer(sup.nextPlayer(g));
					}
					g.setPlayerYellow(null);
					countPlayer--;
				}
			}
			if (g.getPlayerRed() != null) {
				countPlayer++;
				if (g.getPlayerRed().getPlayerName()
						.equals(userNameFromLeaving)) {
					player = g.getPlayerRed();
					gameBoard = deleteCharacterFromGameBoard(gameBoard, player);
					if (g.getCurrentPlayer().equals(player)) {
						g.setCurrentPlayer(sup.nextPlayer(g));
					}
					g.setPlayerRed(null);
					countPlayer--;
				}
			}
			if (g.getPlayerGreen() != null) {
				countPlayer++;
				if (g.getPlayerGreen().getPlayerName()
						.equals(userNameFromLeaving)) {
					player = g.getPlayerGreen();
					gameBoard = deleteCharacterFromGameBoard(gameBoard, player);
					if (g.getCurrentPlayer().equals(player)) {
						g.setCurrentPlayer(sup.nextPlayer(g));
					}
					g.setPlayerGreen(null);
					countPlayer--;
				}
			}
			if (g.getPlayerBlue() != null) {
				countPlayer++;
				if (g.getPlayerBlue().getPlayerName()
						.equals(userNameFromLeaving)) {
					player = g.getPlayerBlue();
					gameBoard = deleteCharacterFromGameBoard(gameBoard, player);
					if (g.getCurrentPlayer().equals(player)) {
						g.setCurrentPlayer(sup.nextPlayer(g));
					}
					g.setPlayerBlue(null);
					countPlayer--;
				}
			}
			r.setMsg("Sie haben das Spiel verlassen");
			r.setReturnCode(0);

			if (player != null) {
				g.setGameBoardAsIntArray(gameBoard);
				g.setRemainingGamePositions(g.getRemainingGamePositions() + 1);

				Highscore score = getHighscore(userNameFromLeaving);
				int newScore = score.getScore() - 1;
				outputBean.updateHighscore(GameType.Ludo.name(),
						userNameFromLeaving, newScore);
				dao.updateGame(g);

				dao.deletePlayer(sessionId);
				r.setMsg("Sie haben 1 Strafpunkt erhalten");
			}

			if (countPlayer == 1) {
				dao.closeGame(gameId);
			}

		} catch (NoGameException e) {
			r.setMsg("Sie konnten das Spiel nicht verlassen");
			r.setReturnCode(e.getErrorCodeNb());
		}
		return r;
	}

	@Override
	public ReturncodeResponse leaveOpenGame(int sessionId, int gameId) {
		ReturncodeResponse r = new ReturncodeResponse();
		try {
			Game g = getGame(gameId);
			LudoSession session = dao.findSessionById(sessionId);
			String userNameFromLeaving = session.getUserName();
			Player player = null;
			boolean playerYellow = true;
			if (g.getPlayerYellow() != null) {
				if (g.getPlayerYellow().getPlayerName()
						.equals(userNameFromLeaving)) {
					player = g.getPlayerYellow();
					g.setPlayerYellow(null);
					playerYellow = false;
				}
			}
			if (g.getPlayerRed() != null) {
				if (g.getPlayerRed().getPlayerName()
						.equals(userNameFromLeaving)) {
					player = g.getPlayerRed();
					g.setPlayerRed(null);
				}
			}
			if (g.getPlayerGreen() != null) {
				if (g.getPlayerGreen().getPlayerName()
						.equals(userNameFromLeaving)) {
					player = g.getPlayerGreen();
					g.setPlayerGreen(null);
				}
			}
			if (g.getPlayerBlue() != null) {
				if (g.getPlayerBlue().getPlayerName()
						.equals(userNameFromLeaving)) {
					player = g.getPlayerBlue();
					g.setPlayerBlue(null);
				}
			}
			r.setMsg("Der Tisch wurde verlassen");
			r.setReturnCode(0);

			if (player != null) {
				dao.updateGame(g);
				dao.deletePlayer(sessionId);
			}

			if (!playerYellow) {
				r.setMsg("Der Tisch wurde aufgelöst");
				dao.closeGame(gameId);
			}

		} catch (NoGameException e) {
			r.setMsg("Sie konnten das Spiel nicht verlassen");
			r.setReturnCode(e.getErrorCodeNb());
		}
		return r;
	}

	private int[] deleteCharacterFromGameBoard(int[] gameBoard,
			Player leavingPlayer) {
		gameBoard[leavingPlayer.getCharacterOne()] = 0;
		gameBoard[leavingPlayer.getCharacterTwo()] = 0;
		gameBoard[leavingPlayer.getCharacterThree()] = 0;
		gameBoard[leavingPlayer.getCharacterFour()] = 0;
		return gameBoard;
	}

	/**
	 * This method delivers the 10 first highscore positions for the specific
	 * game
	 */
	@Override
	public HighscoreResponse getHighscoreList(String game) {
		GameType type = GameType.Ludo;
		HighscoreResponse r = new HighscoreResponse();
		// if (GameType.Ludo.name().equals(game)) {
		ArrayList<Highscore> highscores = dao.getHighscoreList(type);
		ArrayList<String> scores = new ArrayList<>();
		if (highscores != null) {

			for (int i = 0; i < highscores.size(); i++) {
				scores.add("Platz " + (i + 1) + "     "
						+ highscores.get(i).toString());
			}
			String[] resultHighscore = new String[scores.size()];
			for (int i = 0; i < scores.size(); i++) {
				resultHighscore[i] = scores.get(i);
			}
			r.setHighscores(resultHighscore);
			r.setReturnCode(0);
			return r;
		}
		r.setReturnCode(1);
		r.setMsg("Keine Highscores zu diesem Spiel gefunden.");
		return r;
	}
}
